# -*- encoding: utf-8 -*-

# Copyright 2010 István Szentandrási
# <etude-music-player@googlegroups.com>

# This file is part of Etude.
#
# Etude is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as 
# published by the Free Software Foundation, either version 3 
# of the License, or (at your option) any later version.
#
# Etude is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Etude. If not, see <http://www.gnu.org/licenses/>.

from . import _
_b = __builtins__['_']

"""
Default layout plugin
"""
import gtk
import gobject

import etude.plugins as ep
import etude.img as img
import etude.client as client
import etude.gui as gui

class DefaultLayout(ep.PluginLayout):
    """
    class for controlling the layout, managing windows and panel visibility
    """
    _short_name = "Default Layout"
    _show_name = _("Default Layout")
    _version = "0.1"
    _unique = "Default_Layout-0.1" # short name + version is enough, just to identify loaded
    #ASCII chars from 33 - 126
    _config = {'position_x': '0', 'position_y': '0', 'mode': 'full',
               'full_width': '1', 'full_height': '1', 'small_width': '1', 
               'small_height': '1', 'splitter_position': '0.75'}
    _ui = """
        <ui>
            <popup name="mainmenu">
                <menuitem action="preferences" position="bot" />
                <menuitem action="about" position="bot" />
                <separator name="sep_m2" position="bot" />
                <menuitem action="stop_daemon" name="stop_n_quit" position="bot" />
                <menuitem action="quit" position="bot" />
            </popup>
        </ui>
        """

    def __init__(self, control):
        
        self._actions = [
                ('layout_expand', None, _("Toggle minimal mode"), '<Ctrl>m',
                    None, self.toggle_extended_cb)
                ]
        
        ep.PluginLayout.__init__(self, control)
        self.mw = MainWindow(self)
        self.mw.move(int(self.get_config('position_x')), 
                int(self.get_config('position_y')))
        if self.get_config('mode') == 'full':
            self.mw.song_title.set_expanded(True)
            self.mw.resize(int(self.get_config('full_width')),
                           int(self.get_config('full_height')))
        else:
            self.mw.song_title.set_expanded(False)
            self.mw.resize(int(self.get_config('small_width')),
                           int(self.get_config('small_height')))
        self.extended_callback(None)

        self.mw.connect_after("delete_event", self.delete_event)
        self.mw.connect('configure_event', self.window_config_event)
        self.iconified = False
        self.mw.connect('window-state-event', self.window_state_event_cb)
        
        self.mw.equ_button.connect("toggled", self.show_equ)
        
        self.mw.song_title.connect("notify::expanded", self.extended_callback)
 
        self.bind(self.control, "g_plugin_panel_loaded", self.g_plugin_loaded)
        self.bind(self.control, "g_plugin_panel_unloaded",
                self.g_plugin_unloaded)
        self.bind_after( self.control, "g_init_done", self.after_init_done)

    def init_done_idle(self):
        #events done, hopefully we can now set the splitter
        self.on_init_set_splitter()

    def after_init_done(self, widget, data=None):
        gobject.idle_add(self.init_done_idle, priority=gobject.PRIORITY_LOW)

    def on_init_set_splitter(self):
        """
        set the hpaned splitter position
        big thanks to quodlibet developers! for this
        """
        container = self.mw.extended
        try:
            val = float(self.get_config('splitter_position'))
        except:
            val = 0.75
        container.connect("notify::position", self.set_splitter_position)
        
        def set_size(paned, alloc, pos):
            paned.set_relative(pos)
            paned.disconnect(paned._size_sig)
            # The signal disconnects itself! I hate GTK sizing.
            del(paned._size_sig)
        
        sig = container.connect('size-allocate', set_size, val)
        container._size_sig = sig

    def set_splitter_position(self, paned, spec, data=None):
        self.set_config('splitter_position', str(paned.get_relative()))

    def window_config_event(self, widget, event):
        """
        save the last known position and size
        """
        if self.mw.get_property("visible"):
            width, height = self.mw.get_size()
            if self.get_config('mode') == 'full':
                self.set_config('full_width', str(width))
                self.set_config('full_height', str(height))
            else:
                self.set_config('small_width', str(width))
                self.set_config('small_height', str(height))
            x, y = self.mw.get_position()
            self.set_config('position_x', str(x))
            self.set_config('position_y', str(y))
 
    def window_state_event_cb(self, window, event):
        
        if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
            if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
                self.iconified = True
                #window.set_skip_taskbar_hint(True)
                #window.set_skip_pager_hint(True)
            else:
                self.iconified = False
                #window.set_skip_taskbar_hint(True)
                #window.set_skip_pager_hint(True)
        return False
                    
        
    def g_plugin_loaded(self, widget, unique):
        """
        An etude plugin loaded, add it somewhere in the gui
        """
        plugin = self.control.get_plugin(unique)
        key = plugin._type
        if key == ep.E_PANEL_TYPE_PLAYLIST:
            self.plist_panel = plugin
            self.mw.plist_place.add(self.plist_panel)
            self.plist_panel.show()
        elif key == ep.E_PANEL_TYPE_INFO:
            self.info_panel = plugin
            self.mw.append_tab(self.info_panel)
            self.info_panel.show()
            self.mw.notebook.reorder_child(self.info_panel, 2)
        elif key == ep.E_PANEL_TYPE_OTHER:
            self.mw.append_tab(plugin)
            plugin.show()
        elif key == ep.E_PANEL_TYPE_MEDIALIB:
            self.mlib_panel = plugin
            self.mw.append_tab(self.mlib_panel)
            self.mlib_panel.show()
            self.mw.notebook.reorder_child(self.mlib_panel, 0)
        elif key == ep.E_PANEL_TYPE_COLLECTIONS:
            self.coll_panel = plugin
            self.mw.append_tab(self.coll_panel)
            self.coll_panel.show()
            self.mw.notebook.reorder_child(self.coll_panel, 1)
        elif key == ep.E_PANEL_TYPE_EQU:
            self.equ_panel = plugin
            
            self.equ_panel.show()
            self.equ_window = gtk.Window( gtk.WINDOW_TOPLEVEL)
            self.equ_window.set_skip_taskbar_hint(True)
            self.equ_window.set_skip_pager_hint(True)
            self.equ_window.set_type_hint( gtk.gdk.WINDOW_TYPE_HINT_UTILITY)
            self.equ_window.add(self.equ_panel)
            self.mw.connect("button_press_event", self.hide_equ)
            self.equ_window.connect("delete_event", self.hide_equ_true)
            self.equ_window.connect("size-allocate", self.equ_size_changed)
            self.equ_window.set_property("resizable", False)
            self.equ_window.set_property("can-focus", True)
            self.equ_window.set_title(_("Etude")+" - "+_("Equalizer"))
            self.mw.equ_button.show()
        self.mw.check_tabs()

    def g_plugin_unloaded(self, widget, key):
        if key == ep.E_PANEL_TYPE_EQU:
            self.equ_window.destroy()
            self.mw.equ_button.hide()
        self.mw.check_tabs()

    def __position_equ_window(self):
        x_win, y_win = self.mw.equ_button.window.get_origin()
        button_rect = self.mw.equ_button.get_allocation()
        equ_rect = self.equ_panel.get_allocation()
        x_coord, y_coord = (button_rect.x + button_rect.width + 
                x_win - equ_rect.width,
                button_rect.y+y_win)
        width, height = equ_rect.width, equ_rect.height
        self.equ_window.set_size_request(-1, -1)
        self.equ_window.move(max(x_coord, 0), y_coord+button_rect.height)

    def equ_size_changed(self, widget, requisiton):
        self.__position_equ_window()

    def show_equ(self, widget, data = None):
        """
        Show the equalizer window, aline with the equalizer button, if possible
        """
        if self.mw.equ_button.get_active():
            self.__position_equ_window()
            self.equ_window.present()
            #self.equ_window.queue_resize()
            self.equ_window.grab_focus()
        else:
            self.hide_equ()

    def hide_equ(self, widget = None, event = None):
        """
        hide the equalizer window
        """
        try:
            if self.equ_window.get_property("visible"):
                self.equ_window.hide()
            self.mw.equ_button.set_active(False)
        except:
            pass
        return False

    def hide_equ_true(self, widget = None, event = None):
        """
        hide the equ, and return true, se that the equalizer window won't
        be destroyed just hidden
        """
        self.hide_equ(widget, event)
        return True
    
    def delete_event(self, widget, event, data=None):
        """
        if no plugin stopped the application closing, quit the program
        """
        self.control.quit()
        return False

    def toggle_extended_cb(self, ac, data=None):
        """
        Toggle the extended mode
        """
        self.mw.song_title.set_expanded(not self.mw.song_title.get_expanded())

    def extended_callback(self, param_spec, user_data = None):
        """
        Minimal mode toggled clicking the song title
        """
        if self.mw.song_title.get_expanded():
            self.mw.extended.show()
            self.set_config('mode', 'full')
            self.mw.resize(int(self.get_config('full_width')),
                           int(self.get_config('full_height')))
        else:
            self.mw.extended.hide()
            width, height = (int(self.get_config('small_width')),
                             int(self.get_config('small_height')))
            self.mw.resize(width, height)
            self.set_config('mode', 'small')
        return False

    def show_main(self, bool = True):
        """
        Show the main window/present it
        """
        if bool:
            self.mw.move(int(self.get_config('position_x')),
                    int(self.get_config('position_y')))
            self.mw.show()
            #self.mw.set_skip_taskbar_hint(False)
            #self.mw.set_skip_pager_hint(False)
            #self.mw.deiconify()
            self.mw.present()
        else:
            #self.hide_equ()
            #self.mw.set_skip_taskbar_hint(True)
            #self.mw.set_skip_pager_hint(True)
            #self.mw.iconify()
            self.mw.hide()

    def toggle_main(self):
        """
        toggle the main window visibility
        """
        self.show_main(not self.mw.get_property('visible'))

    def get_main_window(self):
        """
        get the main window, use if unnecessary, for example connecting to
        it's delete signal
        """
        return self.mw

    def unload(self):
        ep.PluginLayout.unload(self)
        self.mw.destroy()

def get_image_of_size(name, gtk_size):
    """
    get an image of size defined by gtk size constants (gtk.SIZE_BUTTON etc.)
    """
    image = gtk.Image()
    pixb = img.load_svg_from_egg(__package__, name)
    src = gtk.IconSource()
    src.set_pixbuf(pixb)
    size_pixb = image.style.render_icon(src, gtk.TEXT_DIR_NONE,
            gtk.STATE_NORMAL, size = gtk_size)
    image.set_from_pixbuf(size_pixb)
    return image

ALBUMART_SIZE = 50
class MainWindow(gtk.Window):
    """
    The main window with playback controls
    """


    def __init__(self, layout):
        gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
        self.layout = layout
        self.control = layout.control
        self.client = layout.control.get_client()

        self.set_title(_("Etude Music Player"))
        
        self.set_default_size(450, 480)

        self.vbox = gtk.VBox(False, 0)
        self.vbox.set_property("border-width", 5)
        self.add(self.vbox)

        self.main_table = gtk.Table(rows = 2, columns = 3, homogeneous = False)
        self.vbox.pack_start(self.main_table, False, False, 0)
         
        self.album_art = gtk.Image()
        self.album_art.set_size_request(ALBUMART_SIZE, ALBUMART_SIZE)
        self.main_table.attach(self.album_art, 0, 1, 0, 2,
                xoptions = 0, yoptions = 0)
        self.album_art.show()

        box1 = gtk.HBox(False, 0)
        self.main_table.attach(box1, 1, 2, 0, 1, yoptions = 0)

        control_buttons = [ ("prev", gtk.STOCK_MEDIA_PREVIOUS),
                ("play", gtk.STOCK_MEDIA_PLAY),
                ("pause", gtk.STOCK_MEDIA_PAUSE),
                ("stop", gtk.STOCK_MEDIA_STOP),
                ("next", gtk.STOCK_MEDIA_NEXT)
                ]
    
        for button_name, stock_image in control_buttons:
            butt = gtk.Button()
            act = self.control.actions.get_action(button_name)
            act.connect_proxy(butt)
            gui.format_button(butt, no_label=True, force_image=True,
                    relief=gtk.RELIEF_NONE, stock_image=stock_image)
            box1.pack_start(butt, False, False, 0)

        self.progress_time = gtk.ProgressBar()
        self.progress_time.set_text(_("Not connected"))
        self.progress_eventbox = gtk.EventBox()
        self.progress_eventbox.add(self.progress_time)
        box1.pack_start(self.progress_eventbox)

        self.progress_eventbox.show()
        self.progress_time.show()

        box1.show()

        hbox2 = gtk.HBox()
        hbox2.show()
        self.main_table.attach(hbox2, 1, 2, 1, 2)

        self.song_title = gtk.Expander()
        self.song_title.set_property('can-focus', False)
        self.song_label = gtk.Label(_b("Unknown"))
        self.song_title.set_label_widget(self.song_label)
        hbox2.pack_start(self.song_title, True, True)

        self.song_label.show()
        self.song_title.show()
        #self.song_title.set_expanded(True)


        image = get_image_of_size('img/menu.svg', gtk.ICON_SIZE_BUTTON)
        menu_button = gtk.Button()
        menu_button.set_image(image)
        menu_button.connect('clicked', self.show_main_popup)
        menu_button.set_relief( gtk.RELIEF_NONE )
        menu_button.show()
        hbox2.pack_end(menu_button, False, False)

        self.volume_button = gtk.VolumeButton()
        self.main_table.attach(self.volume_button, 2, 3, 0, 1,
                xoptions = 0, yoptions = 0)
        self.volume_button.show()

        self.equ_button = gtk.ToggleButton()
        equ_img = get_image_of_size('img/equalizer.svg', gtk.ICON_SIZE_BUTTON) 
        self.equ_button.set_relief( gtk.RELIEF_NONE )
        self.equ_button.set_image(equ_img)
        self.main_table.attach(self.equ_button, 2, 3, 1, 2,
                xoptions = 0, yoptions = 0)

        self.main_table.show()

        self.extended = gui.RHPaned()
        self.vbox.pack_start(self.extended)

        self.plist_place = gtk.HBox()
        self.extended.pack2(self.plist_place, resize = False, shrink = True)
        self.plist_place.show()

        self.notebook = gtk.Notebook()
        self.notebook.set_tab_pos(gtk.POS_LEFT)
        self.extended.pack1(self.notebook, resize = True, shrink = True)
        self.notebook.show()
        self.extended.show()
        self.vbox.show()
        self.show()

        self.set_albumart()

        self.volume_button.connect("value-changed", self.volume_set)
        self.progress_eventbox.connect("button-press-event", self.progress_seek)
        #self.progress_eventbox.connect("button-release-event", self.progress_seek)

        self.layout.bind(self.client, "e_playback_status", self.new_status)
        self.layout.bind(self.client, "e_playback_playtime", self.playtime)
        self.layout.bind(self.client, "e_playback_current_id",
                self.song_changed)
        self.layout.bind(self.client, "e_medialib_entry_changed",
                self.entry_changed)
        self.layout.bind(self.client, "e_playback_volume_changed",
                self.volume_changed)

    def show_main_popup(self, widget, data = None):
        def _position(menu, button):
            x, y = self.get_position()
            alloc = button.get_allocation()
            x += alloc.x + int(alloc.width/2)
            y += alloc.y + alloc.height
            return (x, y, True)

        menu = self.control.uimanager.get_widget("/mainmenu")
        menu.popup(None, None, _position, 1, 0, widget)

    def new_status(self, widget, status):
        """
        the playback status changed
        """
        #self.set_progressbar()
        if status == client.PB_STOP:
            self.set_title(_("Etude Music Player"))
        return False

    def playtime(self, widget, playtime):
        """caught a playtime signal"""
        self.set_progressbar(playtime)
        return False

    def set_progressbar(self, playtime = 0):
        """update the playback status progressbar"""
        pb = self.client.playback
        duration = int(max(pb.current_info.get(u'duration'), 0))
        pinterval = client.get_interval(playtime/1000.0)
        try:
            dinterval = client.get_interval(duration/1000.0)
            fr = pb.playtime*1.0/duration
        except:
            dinterval = client.get_interval(0)
            fr = 0
        self.progress_time.set_text(pb.status_string + " " + pinterval +
                " / " + dinterval)
        fr = max(0.0, min(1.0, fr))
        self.progress_time.set_fraction(fr)

    def progress_seek(self, widget, event):
        """seek to a position in the playback"""
        pb = self.client.playback
        pause = False
        if pb.status == client.PB_STOP:
            return False
        duration = pb.current_info.get(u'duration')
        try:
            duration = int(duration)
            if duration == 0:
                return False
        except:
            return False
        size = self.progress_eventbox.get_allocation().width
        ms = event.x*1.0/size*duration
        pb.seek_ms(ms)
        return False

    def entry_changed(self, widget, song_id):
        """the current song changed - update the song"""
        try:
            if song_id == self.client.playback.current_info['id']:
                self.song_changed(widget, song_id)
        except KeyError:
            pass

    def song_changed(self, widget, song_id):
        """
        if the song changed, set the title and albumart, if available
        """
        def escape_title(text):
            return text.replace('&amp;', '&');
        nfo = self.client.playback.current_info
        text = ""
        row = nfo.get_custom_info('<smart>|{'  +_('by') + ' <artist>}{ ' +
                _("from") + ' <album>}') 
        text = '<b>'+row[0]+'</b>'
        if row[1] != '':
            text += "\n"+row[1]
        self.song_label.set_markup(text)
        self.set_title(_("Etude")+" - "+escape_title(row[0]))
        if nfo.has_key('picture_front'):
            self.set_albumart(hash = nfo['picture_front'])
        else:
            self.set_albumart()
        return False
        
    def set_albumart(self, pixbuf = None, hash = None):
        """get the albumart from the server and resize it"""
        def _bindata_cb(value):
            pb = img.get_pixbuf_from_data(value)
            self.set_albumart(pixbuf = pb)
        size = self.main_table.get_allocation().height
        #size = ALBUMART_SIZE
        if hash != None:
            self.client.bindata.retrieve(hash, _bindata_cb)
            return
        elif pixbuf == None:
            pixbuf = gtk.icon_theme_get_default().load_icon("etude", size, 0)
        pixbuf, w, h = img.get_pixbuf_of_size(pixbuf, size)
        self.album_art.set_from_pixbuf(pixbuf)
        self.album_art.set_size_request(w, h)
        #self.hbox.resize_children()
        #self.main_table.resize_children()

        
    def volume_set(self, widget, value, data = None):
        """set the playback volume"""
        self.client.playback.volume_set(round(value*100))
        return False

    def volume_changed(self, widget, vol):
        """the volume was set by somebody else/by the server"""
        vol_m = max(vol.values())
        self.volume_button.set_value(vol_m/100.0)
        return False

    def append_tab(self, child):
        """append a tab to the left tabbar"""
        try:
            title = child._title
        except:
            title = "tab%i" % self.notebook.get_n_pages()
        label = gtk.Label(title)
        label.set_angle(90)
        self.notebook.append_page(child, tab_label = label)

    def check_tabs(self):
        """check the positions"""
        ntabs = self.notebook.get_n_pages()
        if ntabs > 0:
            self.notebook.show()
        else:
            self.notebook.hide()
        #self.extended.set_position(-1)



